package xj.graph2d.app;

import static xj.app.BaseApplicationFrame.getResourceString;
import static xj.app.BaseApplicationFrame.createSplashScreen;
import static xj.app.BaseApplicationFrame.hideSplashScreen;
import static xj.app.BaseApplicationFrame.setSplashScreenProgress;
import static xj.app.BaseApplicationFrame.startApp;
import static xj.app.BaseApplicationFrame.initGUI;
import static xj.graph2d.DocumentConstants.DEFAULT_FILE_TYPE;
import static xj.graph2d.DocumentConstants.SERIALIZATION_FILE_TYPE;
import static xj.graph2d.DocumentConstants.UNKNOWN_FILE_TYPE;
import static xj.graph2d.DocumentConstants.XML_FILE_TYPE;
import static xj.model.uml.UMLModelConstants.UML_MODEL_ADDER_NAMES;
import static xj.model.uml.UMLModelConstants.UML_MODEL_CLASSES;
import static xj.util.xml.XMLUtil.parseXMLDocument;
import static xj.util.xml.XMLUtil.stripWhiteSpace;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.JComponent;
import javax.swing.JMenuBar;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultMutableTreeNode;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import xj.app.BaseApplicationFrame;
import xj.app.DrawToolkit;
import xj.graph2d.BoxGroup;
import xj.graph2d.CompoundDrawShape;
import xj.graph2d.Document;
import xj.graph2d.DrawShapeConstants;
import xj.graph2d.DrawShapeFactory;
import xj.graph2d.EllipseShape;
import xj.graph2d.GraphDocument;
import xj.graph2d.Group;
import xj.graph2d.LineShape;
import xj.graph2d.RectangleShape;
import xj.graph2d.RectangularGroup;
import xj.graph2d.SimpleDrawDocument;
import xj.graph2d.TextShape;
import xj.graph2d.shapes.BoxLabel;
import xj.graph2d.shapes.CircleShape;
import xj.graph2d.shapes.CompartmentalRectangleShape;
import xj.graph2d.shapes.CompartmentalRoundRectangleShape;
import xj.graph2d.shapes.CubicCurveSelfLoop;
import xj.graph2d.shapes.CubicCurveShape;
import xj.graph2d.shapes.DisjointGroup;
import xj.graph2d.shapes.GraphEdgeShape;
import xj.graph2d.shapes.IconShape;
import xj.graph2d.shapes.ImageShape;
import xj.graph2d.shapes.OrthogonalLineShape;
import xj.graph2d.shapes.OrthogonalSelfLoop;
import xj.graph2d.shapes.OrthogonalSelfLoop4;
import xj.graph2d.shapes.PolyCurveSelfLoop;
import xj.graph2d.shapes.PolyCurveShape;
import xj.graph2d.shapes.PolyLineShape;
import xj.graph2d.shapes.PolygonShape;
import xj.graph2d.shapes.QuadCurveShape;
import xj.graph2d.shapes.RegularPolygonShape;
import xj.graph2d.shapes.RotatableCompoundDrawShape;
import xj.graph2d.shapes.RoundRectangleShape;
import xj.graph2d.shapes.SVGShape;
import xj.graph2d.shapes.ScalableCompoundDrawShape;
import xj.graph2d.shapes.ScribbleShape;
import xj.graph2d.shapes.ShapeConstants;
import xj.graph2d.tools.CurveTool;
import xj.graph2d.tools.GraphEdgeTool;
import xj.graph2d.tools.GraphNodeTool;
import xj.graph2d.tools.GraphPolyEdgeTool;
import xj.graph2d.tools.GroupTool;
import xj.graph2d.tools.MultiPointTool;
import xj.graph2d.tools.OnePointShapeTool;
import xj.graph2d.tools.PolyShapeDrawTool;
import xj.graph2d.tools.SelectionTool;
import xj.graph2d.tools.SimpleDrawTool;
import xj.graph2d.tools.TextTool;
import xj.graph2d.tools.UMLPointTool;
import xj.meta.ModelBuilder;
import xj.meta.ModelElement;
import xj.meta.StereotypeManager;
import xj.util.gui.ExtensionFileFilter;
import xj.util.xml.ErrorMessageHandler;

public class GraphApp extends DrawApp {

  public GraphApp(BaseApplicationFrame frame) {      
    super(frame);
    gapp = this;
  }

  protected void initDocView() {
    GraphAppDocument gdoc = new GraphAppDocument(this);
    doc = gdoc;
    view = new GraphAppView(this, gdoc);
    view.setShowRuler(showRuler);
  }

  protected void initDocView(SimpleDrawDocument doc) {
    if (doc != null) { 
      this.doc = doc;
      view = doc.makeView();
      view.setShowRuler(showRuler);   
     } else { 
      initDocView();
    }
  } 

  protected void initDrawShapeFactory(DrawShapeFactory factory) {
    if (factory != null) {
      factory.addPrototype("LineShape", new LineShape(true));
      factory.addPrototype("RectangleShape", new RectangleShape(false, true));
      factory.addPrototype("FilledRectangleShape", new RectangleShape(true, true));
      factory.addPrototype("RoundRectangleShape", new RoundRectangleShape(false, true));
      factory.addPrototype("FilledRoundRectangleShape",
			   new RoundRectangleShape(true, true));
      factory.addPrototype("EllipseShape", new EllipseShape(false, true));
      factory.addPrototype("FilledEllipseShape", new EllipseShape(true, true));
      factory.addPrototype("CircleShape", new CircleShape(true));
      factory.addPrototype("ScribbleShape", new ScribbleShape());
      factory.addPrototype("PolygonShape", new PolygonShape(false, true));
      factory.addPrototype("PolyLineShape", new PolyLineShape(true));
      factory.addPrototype("QuadCurveShape", new QuadCurveShape(true));
      factory.addPrototype("CubicCurveShape", new CubicCurveShape(true));
      factory.addPrototype("CubicCurveSelfLoop", new CubicCurveSelfLoop(true));
      factory.addPrototype("PolyCurveShape", new PolyCurveShape(true));
      factory.addPrototype("PolyCurveSelfLoop", new PolyCurveSelfLoop(true));
      factory.addPrototype("OrthogonalLineShape", new OrthogonalLineShape(true));
      factory.addPrototype("OrthogonalSelfLoop", new OrthogonalSelfLoop(true));
      factory.addPrototype("OrthogonalSelfLoop4", new OrthogonalSelfLoop4(true));
      factory.addPrototype("CompartmentalRectangleShape",
			   new CompartmentalRectangleShape(true));
      factory.addPrototype("CompartmentalRoundRectangleShape",
			   new CompartmentalRoundRectangleShape(true));
      factory.addPrototype("GraphEdgeShape", new GraphEdgeShape(true));
      // factory.addPrototype("TitledShape", new TitledShape());

      TextShape t;
      factory.addPrototype("TextShape", t = new TextShape());
      t.showCursor(true);
      factory.addPrototype("TextBox", new BoxGroup());

      factory.addPrototype("ImageShape", new ImageShape());
      factory.addPrototype("SVGShape", new SVGShape());
      factory.addPrototype("IconShape", new IconShape());

      factory.addPrototype("RectangularShape",
			   new xj.graph2d.shapes.RectangularShape());
      factory.addPrototype("RegularPolygonShape", new RegularPolygonShape());

      factory.addPrototype("CompoundDrawShape", new CompoundDrawShape());
      factory.addPrototype("Group", new Group());
      factory.addPrototype("BoxGroup", new BoxGroup());
      factory.addPrototype("BoxLabel", new BoxLabel());
      factory.addPrototype("RectangularGroup", new RectangularGroup());
      factory.addPrototype("DisjointGroup", new DisjointGroup());

      factory.addPrototype("ScalableCompoundDrawShape",
			   new ScalableCompoundDrawShape());
      factory.addPrototype("RotatableCompoundDrawShape",
			   new RotatableCompoundDrawShape());

      factory.addPrototype("LifeLineShape",
			   new xj.graph2d.shapes.uml.LifeLineShape(true));

      ModelBuilder.addElements(UML_MODEL_CLASSES);
      ModelBuilder.addAdderNames(UML_MODEL_ADDER_NAMES);
    }
  }

  public void addTool(String name, SimpleDrawTool tool, SimpleDrawTool switchTool) {
    if (toolkit != null && tool != null) {
      if (switchTool != null) { 
	tool.setSwitchTool(switchTool);
      }
      toolkit.addTool(name, tool);      
    }
  }

  protected void initToolkit() {
    toolkit = new DrawToolkit(512);

    DrawShapeFactory factory = DrawShapeFactory.getInstance();
    initDrawShapeFactory(factory);

    // addTool("Point", new GraphPointTool());
    SimpleDrawTool pointTool = new MultiPointTool(new UMLPointTool(), new SelectionTool());
    addTool("Point", pointTool);
	    
    addTool("Group", new GroupTool());

    // addTool("LineEdge", new TwoEndsDrawTool(new LineShape(), true,
    // "LineEdge"));
    addTool("LineEdge", 
	    new GraphEdgeTool(new LineShape(true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR, 
			      "LineEdge"),
	    pointTool);
    addTool("ArcEdge", 
	    new CurveTool(new QuadCurveShape(true),
			  DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR, 
			  "ArcEdge"),
	    pointTool);
    addTool("CurveEdge", 
	    new CurveTool(new CubicCurveShape(true),
			  DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR, 
			  "CurveEdge"),
	    pointTool);

    addTool("PolyLineEdge", 
	    new GraphPolyEdgeTool(new PolyLineShape(true),
				  DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR, 
				  "PolyLineEdge"),
	    pointTool);
    addTool("PolyCurveEdge", 
	    new GraphPolyEdgeTool(new PolyCurveShape(true),
				  DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR, 
				  "PolyCurveEdge"),
	    pointTool);
    addTool("OrthogonalEdge", 
	    new GraphPolyEdgeTool(new OrthogonalLineShape(true),
				  DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR, 
				  "OrthogonalEdge"),
	    pointTool);

    addTool("Polygon", 
	    new PolyShapeDrawTool((PolygonShape) factory.getPrototype("PolygonShape"),
				  DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR, 
				  "Polygon"),
	    pointTool);

    // addTool("RectNode", new TwoEndsDrawTool(new RectangleShape(), true,
    // "RectNode"));
    addTool("RectNode", 
	    new GraphNodeTool(new RectangleShape(0, 0, 20, 30, false, true), 
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);
    // "RectNode"));

    addTool("EllipseNode", 
	    new GraphNodeTool(new EllipseShape(0, 0, 30, 20, false, true), 
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);
    addTool("RoundRectNode", 
	    new GraphNodeTool(new RoundRectangleShape(0, 0, 40, 60, false, true), 
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    addTool("Circle", 
	    new GraphNodeTool(new CircleShape(0, 0, 30, false, true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    addTool("Actor", 
	    new GraphNodeTool(new xj.graph2d.shapes.RectangularShape(ShapeConstants.ACTOR_SHAPE, 
								     ShapeConstants.NORTH, 
								     0, 0, 30, 40, true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);
    addTool("DBox", 
	    new GraphNodeTool(new xj.graph2d.shapes.RectangularShape(ShapeConstants.DBOX_SHAPE, 
								     ShapeConstants.NORTH, 
								     0, 0, 40, 30, true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);
    addTool("Triangle", 
	    new GraphNodeTool(new xj.graph2d.shapes.RectangularShape(ShapeConstants.TRIANGLE_SHAPE,
								     ShapeConstants.NORTH, 
								     0, 0, 20, 20, true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);
    addTool("Diamond", 
	    new GraphNodeTool(new xj.graph2d.shapes.RectangularShape(ShapeConstants.DIAMOND_SHAPE,
								     ShapeConstants.NORTH, 
								     0, 0, 20, 20, true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    addTool("Trapezoid", 
	    new GraphNodeTool(new xj.graph2d.shapes.RectangularShape(ShapeConstants.TRAPEZOID_SHAPE,
								     ShapeConstants.NORTH, 
								     0, 0, 20, 20, true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    addTool("Parallelogram", 
	    new GraphNodeTool(new xj.graph2d.shapes.RectangularShape(ShapeConstants.PARALLELOGRAM_SHAPE, 
								     ShapeConstants.NORTH, 
								     0, 0, 20, 20, true), 
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    addTool("House", 
	    new GraphNodeTool(new xj.graph2d.shapes.RectangularShape(ShapeConstants.HOUSE_SHAPE, 
								     ShapeConstants.NORTH, 
								     0, 0, 20, 20, true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    addTool("Cave", 
	    new GraphNodeTool(new xj.graph2d.shapes.RectangularShape(ShapeConstants.CAVE_SHAPE, 
								     ShapeConstants.NORTH, 
								     0, 0, 20, 20, true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    addTool("Hexagon", 
	    new GraphNodeTool(new xj.graph2d.shapes.RectangularShape(ShapeConstants.HEXAGON_SHAPE,
								     ShapeConstants.NORTH, 
								     0, 0, 20, 20, true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    addTool("Octagon", 
	    new GraphNodeTool(new xj.graph2d.shapes.RectangularShape(ShapeConstants.OCTAGON_SHAPE,
								     ShapeConstants.NORTH, 
								     0, 0, 20, 20, true),
			      DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    addTool("Text", new TextTool(DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    /*
    ImageShapeListener listener = new ImageShapeListener();
    listener.setCurrentDirectory(DrawApp.defaultDir);
    addTool("Image", 
	    new OnePointShapeTool((ImageShape) factory.getPrototype("ImageShape"), listener,
				  DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR));
    */
    addTool("ImageTool", 
	    new OnePointShapeTool((ImageShape) factory.getPrototype("ImageShape"), 
				  DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);
    addTool("SVGTool", 
	    new OnePointShapeTool((SVGShape) factory.getPrototype("SVGShape"), 
				  DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR),
	    pointTool);

    view.setDrawToolkit(toolkit);
    // toolkit.setCurrentTool("LineEdge", view);
    toolkit.setCurrentTool("Point", view);
  }

  protected void exportModel(String filename) {
    if (doc instanceof GraphDocument) {
      GraphDocument graph = (GraphDocument) doc;
      graph.exportModel(filename, true);
    }
  }

  protected void exportXMI(String filename) {
    if (doc instanceof GraphDocument) {
      GraphDocument graph = (GraphDocument) doc;
      graph.exportXMI(filename, true);
    }
  }

  /*
   * Load stereotypes from a file
   */
  public void loadStereotypes(String filename) {
    // System.out.println("loadStereotypes: " + filename);

    try {
      InputStream in = null;
      in = new FileInputStream(filename);
      org.w3c.dom.Document doc = null;
      if (in != null) {
	ErrorMessageHandler errorHandler = new ErrorMessageHandler(filename);
	doc = parseXMLDocument(in, errorHandler, false);
	if (errorHandler.hasErrorOrWarning()) {

	}
      }

      if (doc != null) {
	Element docElement = doc.getDocumentElement();
	stripWhiteSpace(docElement);
	if ("Stereotypes".equals(docElement.getLocalName())) {
	  if (docElement.hasChildNodes()) {
	    StereotypeManager stManager = StereotypeManager.getInstance();

	    NodeList nodes = docElement.getChildNodes();
	    if (nodes != null) {
	      int n = nodes.getLength();
	      for (int i = 0; i < n; i++) {
		Node node = nodes.item(i);
		if (node.getNodeType() == Node.ELEMENT_NODE) {
		  Element e = (Element) node;
		  String name = e.getLocalName();
		  if ("Stereotype".equals(name)) {
		    String element = e.getAttribute("element");
		    String stname = e.getAttribute("name");
		    if (element != null && element.length() > 0
			&& stname != null && stname.length() > 0) {
		      stManager.addAvailableStereotype(element, stname);

		      // System.out.println("add
		      // stereotype: " + element + " " +
		      // name);
		    }
		  }
		}
	      }
	    }
	  }
	}

      }

    } catch (IOException e) {
      System.err.println("Error reading file " + filename + ": "
			 + e.getMessage());
      if (debug) {
	e.printStackTrace(System.err);
      }
    } catch (SAXParseException e) {
      // error in input
      System.err.println("Error " + filename + ":" + e.getMessage());
      if (debug) {
	e.printStackTrace(System.err);
      }
    } catch (SAXException e) {
      // error in input
      System.err.println("Error " + filename + ":" + e.getMessage());
      if (debug) {
	e.printStackTrace(System.err);
      }
    }
  }

  public String getDocumentExtension(Document.DocumentType type) {
    return modelFileExtension;
  }

  public static final String graphFileExtension = "gml";

  public static final String modelFileExtension = "vml";

  public static final String xmiFileExtension = "xmi";

  public static final String graphFileDescription = "Graph files (*.gml)";

  public static final String modelFileDescription = "Visual Modeler files (*.vml)";

  public static final String xmiFileDescription = "XML Metadata Interchange files (*.xmi)";

  public static final ExtensionFileFilter graphFileFilter = 
    new ExtensionFileFilter(graphFileExtension, graphFileDescription, XML_FILE_TYPE);

  public static final ExtensionFileFilter modelFileFilter = 
    new ExtensionFileFilter(modelFileExtension, modelFileDescription, XML_FILE_TYPE);

  public static final ExtensionFileFilter xmiFileFilter = 
    new ExtensionFileFilter(xmiFileExtension, xmiFileDescription, XML_FILE_TYPE);

  protected static final FileFilter[] graphFileFilters = {
    // defaultFileFilter,
    // graphFileFilter,
    modelFileFilter };

  protected FileFilter[] getSupportedFileFilters() {
    return graphFileFilters;
  }

  public static int getFiletype(String ext) {
    if (ext != null) {
      if (defaultFileExtension.equals(ext)) {
	return DEFAULT_FILE_TYPE;
      } else if (xmlFileExtension.equals(ext) || graphFileExtension.equals(ext)
		 || modelFileExtension.equals(ext)) {
	return XML_FILE_TYPE;
      } else if (serializationFileExtension.equals(ext)) {
	return SERIALIZATION_FILE_TYPE;
      }
    }
    return UNKNOWN_FILE_TYPE;
  }

  public static String getExtension(int filetype) {
    if (filetype == DEFAULT_FILE_TYPE) {
      return defaultFileExtension;
    } else if (filetype == XML_FILE_TYPE) {
      // return xmlFileExtension;
      return modelFileExtension;
    } else if (filetype == SERIALIZATION_FILE_TYPE) {
      return serializationFileExtension;
    }
    return null;
  }

  public static void main(String[] args) {
    //System.out.println(System.getProperty("java.library.path"));
    //System.setProperty("swt.library.path", "swt.jar");
    //System.setProperty("java.library.path", System.getProperty("java.library.path") + ":/home/jia/ZOOMDev/draw/lib");
    startApp(args, "resources.graph2d.app.DrawApp");

    try { 
      SwingUtilities.invokeAndWait(new Runnable() {
	  public void run() {
	    initGUI(); 

	    createSplashScreen("/icons/splashDraw.jpg");
	    setSplashScreenProgress(20);

	    BaseApplicationFrame frame = new BaseApplicationFrame();
	    gapp = new GraphApp(frame);
	    frame.setApplication(gapp);
	    setSplashScreenProgress(100);
	    frame.setFrame();
	    hideSplashScreen();
	  }
	});
    } catch (Exception e) {   
    
    }
  }

  //private static BaseApplicationFrame frame;
  private static GraphApp gapp;

  public static GraphApp getDrawApp() { 
    return gapp;
  }

  public static JMenuBar getDrawAppMenuBar(){
    return gapp.getAppMenuBar();
  }

  public static JComponent getCenter(){
    return gapp.getAppComponent();
  }

  public static JComponent getTop(){
    return gapp.getAppToolBar();
  }

  public static JComponent getBottom(){
    return gapp.getAppStatusBar();
  }

  public static ModelElement getRoot(){
    SimpleDrawDocument doc = gapp.getDoc();
	  
    if (doc instanceof GraphDocument) {
      GraphDocument graph = (GraphDocument) doc;
      ModelElement model = graph.getModel();
      return model;
    } else {
      return null;
    }
  }

  public static SimpleDrawDocument getRootDocument(){
    return gapp.getDoc();
  }
  
  public static final boolean debug = false;

}

class PrintGraphListener extends DrawAction implements ActionListener {

  public void actionPerformed(ActionEvent e) {

    if (DrawApp.debug) {
      System.out.println("PrintGraphListener.actionPerformed()");
    }

    SimpleDrawDocument doc = main.getDoc();
    if (doc instanceof GraphDocument) {
      GraphDocument graph = (GraphDocument) doc;
      // PrintWriter out = new PrintWriter(new
      // OutputStreamWriter(System.out));
      // graph.printGraph(out);
      // out.flush();
      graph.print();
    }

  }

}

class PrintShapesListener extends DrawAction implements ActionListener {

  public void actionPerformed(ActionEvent e) {

    if (DrawApp.debug) {
      System.out.println("PrintShapeListener.actionPerformed()");
    }

    SimpleDrawDocument doc = main.getDoc();
    doc.dump();
  }

}

class PrintModelListener extends DrawAction implements ActionListener {

  public void actionPerformed(ActionEvent e) {

    if (DrawApp.debug) {
      System.out.println("PrintModelListener.actionPerformed()");
    }

    SimpleDrawDocument doc = main.getDoc();
    if (doc instanceof GraphDocument) {
      GraphDocument graph = (GraphDocument) doc;
      graph.dumpModel();
    }
  }

}

class ShowModelTreeListener extends DrawAction implements ActionListener {

  public void actionPerformed(ActionEvent e) {
    //System.out.println("ShowModelTreeListener.actionPerformed()");

    SimpleDrawDocument doc = main.getDoc();
    if (doc instanceof GraphDocument) {
      GraphDocument graph = (GraphDocument) doc;
      graph.constructModel();
      ModelElement model = graph.getModel();
      DefaultMutableTreeNode root = buildTree(model);
      JTree tree = new JTree(root);
      tree.setShowsRootHandles(true);

      JFrame frame = new JFrame("Show Model Tree");
      frame.setSize(600, 400);
      JScrollPane scroll = new JScrollPane(tree);
      frame.getContentPane().add(scroll, BorderLayout.CENTER);
      frame.setVisible(true);
    }
  }

  private DefaultMutableTreeNode buildTree(ModelElement e) { 
    if (e != null) { 
      String role = e.getRoleInOwner();
      String name = e.getElementName(); 
      if (role != null) { 
	name = role + " : " + name; 
      }
      name += (" [" + e.getId() + "]");
      ModelElement owner = e.getOwner();
      if (owner != null) { 
	name += (" owner=" + owner.getId()); 
      } else { 
	name += " owner=null"; 
      }

      DefaultMutableTreeNode root = new DefaultMutableTreeNode(name);

      Set<String> attributeNames = e.getAllAttirbuteNames();
      Iterator<String> iter = attributeNames.iterator();
      while (iter.hasNext()) {
	String attrName = iter.next();
	Object attrValue = e.getAttribute(attrName);
	DefaultMutableTreeNode attr = new DefaultMutableTreeNode(attrName + " = " + attrValue); 
	root.add(attr);
      }
    
      List<ModelElement> elements = e.getOwnedElements();
      Iterator<ModelElement> eiter = elements.iterator();
      while (eiter.hasNext()) {
	ModelElement e1 = eiter.next();
	root.add(buildTree(e1));
      }
      return root; 
    }
    return null;
  }

}

class ExportModelListener 
  extends DrawAction 
  implements ActionListener {

  JFileChooser chooser = null;

  public ExportModelListener() {
  }

  public void init() {
    /*
     * if (main != null) {
     * chooser.addChoosableFileFilter(DrawApp.xmlFileFilter);
     * chooser.setCurrentDirectory(new File(main.getDefaultDir())); }
     */
  }

  public void actionPerformed(ActionEvent e) {
    export();
  }

  public void export() {
    if (chooser == null) {
      chooser = new JFileChooser();
      chooser.addChoosableFileFilter(DrawApp.xmlFileFilter);
      chooser.setCurrentDirectory(new File(main.getDefaultDir()));
    }

    SimpleDrawDocument doc = main.getDoc();
    if (doc instanceof GraphDocument) {
      GraphDocument graph = (GraphDocument) doc;
      int filetype = XML_FILE_TYPE;
      ExtensionFileFilter filter = DrawApp.xmlFileFilter;
      String ext = filter.getExtension();
      String filename = main.getCurrentFilename();
      int i = filename.lastIndexOf('.');
      if (i > 0 && i < filename.length() - 1) {
	filename = filename.substring(0, i);
      }
      filename += ("." + ext);
      chooser.rescanCurrentDirectory();
      chooser.setSelectedFile(new File(filename));
      int retval = chooser.showDialog(null, getResourceString("ExportModel.text"));
      if (retval == JFileChooser.APPROVE_OPTION) {
	File theFile = chooser.getSelectedFile();
	if (theFile != null) {
	  if (!theFile.isDirectory()) {
	    filename = chooser.getSelectedFile().getAbsolutePath();
	    String fext = null;
	    i = filename.lastIndexOf('.');
	    int j = filename.lastIndexOf(File.separator);
	    if (i > j && i < filename.length() - 1) {
	      fext = filename.substring(i + 1).toLowerCase();
	    }
	    if (ext != null) {
	      if (fext != null) {
		if (!ext.equals(fext)) {
		  // filename += ("." + ext);
		  filename = filename.substring(0, i) + "." + ext;
		}
	      } else {
		filename += ("." + ext);
	      }
	    }

	    graph.exportModel(filename, true);
	  }
	}
      }
    }
  }

}

class ExportXMIListener extends DrawAction implements ActionListener {

  JFileChooser chooser = null;

  public ExportXMIListener() {
  }

  public void init() {
    /*
     * if (main != null) {
     * chooser.addChoosableFileFilter(GraphApp.xmiFileFilter);
     * chooser.setCurrentDirectory(new File(main.getDefaultDir())); }
     */

  }

  public void actionPerformed(ActionEvent e) {
    export();
  }

  public void export() {
    if (chooser == null) {
      chooser = new JFileChooser();
      chooser.addChoosableFileFilter(GraphApp.xmiFileFilter);
      chooser.setCurrentDirectory(new File(main.getDefaultDir()));
    }

    SimpleDrawDocument doc = main.getDoc();
    if (doc instanceof GraphDocument) {
      GraphDocument graph = (GraphDocument) doc;
      int filetype = XML_FILE_TYPE;
      ExtensionFileFilter filter = GraphApp.xmiFileFilter;
      String ext = filter.getExtension();
      String filename = main.getCurrentFilename();
      int i = filename.lastIndexOf('.');
      if (i > 0 && i < filename.length() - 1) {
	filename = filename.substring(0, i);
      }
      filename += ("." + ext);
      chooser.rescanCurrentDirectory();
      chooser.setSelectedFile(new File(filename));
      int retval = chooser.showDialog(null, getResourceString("ExportXMI.text"));
      if (retval == JFileChooser.APPROVE_OPTION) {
	File theFile = chooser.getSelectedFile();
	if (theFile != null) {
	  if (!theFile.isDirectory()) {
	    filename = chooser.getSelectedFile().getAbsolutePath();
	    String fext = null;
	    i = filename.lastIndexOf('.');
	    int j = filename.lastIndexOf(File.separator);
	    if (i > j && i < filename.length() - 1) {
	      fext = filename.substring(i + 1).toLowerCase();
	    }
	    if (ext != null) {
	      if (fext != null) {
		if (!ext.equals(fext)) {
		  // filename += ("." + ext);
		  filename = filename.substring(0, i) + "." + ext;
		}
	      } else {
		filename += ("." + ext);
	      }
	    }

	    graph.exportXMI(filename, true);
	  }
	}
      }
    }
  }

}

class ExportProjectModelListener extends DrawAction implements ActionListener {

  JFileChooser chooser = null;

  public ExportProjectModelListener() {
  }

  public void init() {
    /*
     * if (main != null) {
     * chooser.addChoosableFileFilter(DrawApp.xmlFileFilter);
     * chooser.setCurrentDirectory(new File(main.getDefaultDir())); }
     */
  }

  public void actionPerformed(ActionEvent e) {
    export();
  }

  public void export() {
    /*
     * 
     * if (chooser == null) { chooser = new JFileChooser();
     * chooser.addChoosableFileFilter(DrawApp.xmlFileFilter);
     * chooser.setCurrentDirectory(new File(main.getDefaultDir())); }
     * 
     * SimpleDrawDocument doc = main.getDoc(); if (doc instanceof
     * GraphDocument) { GraphDocument graph = (GraphDocument) doc;
     * 

     * chooser.rescanCurrentDirectory(); chooser.setSelectedFile(new
     * File(main.normalizeFilename(main.getCurrentFilename()))); int retval =
     * chooser.showDialog(null,
     * getResourceString("ExportModel.text")); if (retval ==
     * JFileChooser.APPROVE_OPTION) { File theFile =
     * chooser.getSelectedFile(); if (theFile != null) { if
     * (!theFile.isDirectory()) { String filename =
     * chooser.getSelectedFile().getAbsolutePath(); int filetype =
     * DrawApp.XML_FILE_TYPE; ExtensionFileFilter filter =
     * DrawApp.xmlFileFilter; String ext = filter.getExtension();
     * 
     * String fext = null; int i = filename.lastIndexOf('.'); if (i > 0 && i <
     * filename.length()-1) { fext = filename.substring(i+1).toLowerCase(); }
     * if (ext != null) { if (fext != null) { if (!ext.equals(fext)) {
     * //filename += ("." + ext); filename = filename.substring(0, i) + "." +
     * ext; } } else { filename += ("." + ext); } }
     * 
     * graph.exportModel(filename, true); } } } }
     * 
     */
  }

}

class ExportProjectXMIListener extends DrawAction implements ActionListener {

  JFileChooser chooser = null;

  public ExportProjectXMIListener() {
  }

  public void init() {
    /*
     * if (main != null) {
     * chooser.addChoosableFileFilter(GraphApp.xmiFileFilter);
     * chooser.setCurrentDirectory(new File(main.getDefaultDir())); }
     */
  }

  public void actionPerformed(ActionEvent e) {
    export();
  }

  public void export() {
    /*
     * 
     * if (chooser == null) { chooser = new JFileChooser();
     * chooser.addChoosableFileFilter(GraphApp.xmiFileFilter);
     * chooser.setCurrentDirectory(new File(main.getDefaultDir())); }
     * 
     * SimpleDrawDocument doc = main.getDoc(); if (doc instanceof
     * GraphDocument) { GraphDocument graph = (GraphDocument) doc;
     * 
     * chooser.rescanCurrentDirectory(); chooser.setSelectedFile(new
     * File(main.normalizeFilename(main.getCurrentFilename()))); int retval =
     * chooser.showDialog(null,
     * getResourceString("ExportXMI.text")); if (retval ==
     * JFileChooser.APPROVE_OPTION) { File theFile =
     * chooser.getSelectedFile(); if (theFile != null) { if
     * (!theFile.isDirectory()) { String filename =
     * chooser.getSelectedFile().getAbsolutePath(); int filetype =
     * DrawApp.XML_FILE_TYPE; ExtensionFileFilter filter =
     * GraphApp.xmiFileFilter; String ext = filter.getExtension();
     * 
     * String fext = null; int i = filename.lastIndexOf('.'); if (i > 0 && i <
     * filename.length()-1) { fext = filename.substring(i+1).toLowerCase(); }
     * if (ext != null) { if (fext != null) { if (!ext.equals(fext)) {
     * //filename += ("." + ext); filename = filename.substring(0, i) + "." +
     * ext; } } else { filename += ("." + ext); } }
     * 
     * graph.exportXMI(filename, true); } } } }
     */
  }

}




